home *** CD-ROM | disk | FTP | other *** search
- /* input.c -- input processing */
-
- /*
- * srouted -- silent routing daemon
- * Copyright (C) 1995 Kevin Buhr
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #ifndef lint
- static char rcsid[] = "$Id: input.c,v 1.5 1995/02/20 17:45:38 buhr Exp $";
- #endif /* not lint */
-
- #include "defs.h"
- #include "table.h"
- #include "kernel.h"
- #include "output.h"
- #include "input.h"
-
- #include <netinet/in.h>
-
- static int in_czentry(struct rip *rip, int entry);
-
-
- /*
- * Count number of entries in a RIP packet
- */
-
- int in_countentries( int length )
- {
- return ( length - sizeof( ((struct rip *)NULL)->rip_cmd )
- - sizeof( ((struct rip *)NULL)->rip_vers )
- - sizeof( ((struct rip *)NULL)->rip_res1 ) )
- / sizeof( ((struct rip *)NULL)->rip_nets[0] );
- }
-
-
- /*
- * Check reserved areas in an entry
- */
-
- static int in_czentry(struct rip *rip, int entry)
- {
- int i;
-
- for(i=0; i<14; i++) {
- if(i==2) i=6; /* skip IP address */
- if(rip->rip_nets[entry].rip_dst.sa_data[i]) return(1);
- }
- return(0);
- }
-
-
- /*
- * Process a received RIP packet
- */
-
- void in_processrip(struct rip *rip, int length, struct sockaddr *safrom)
- {
- int entry, entry_count;
- struct netinfo *ni;
- int ev=0; /* if 1, then packet is of "expected" version */
- struct tb_address from, dest;
- short cost;
- int route, netroute, samegw;
-
- from.tba_addr = *safrom;
- tb_chkaddr(&from);
-
- note0( ERCIN_GOTINPUT );
-
- /* this must be from a valid, single-host address */
- if( (from.tba_flags & TBAF_VALID)==0
- || (from.tba_flags & TBAF_HOST)==0 ) {
- warn0(ERCIN_BADFROM);
- return;
- }
-
- #define CZI(thing) \
- if(ev && (thing)!=0) { warn3(ERCIN_CZ,rip,length,&from); goto ignore_rip; }
- #define CZE(rip,entry) \
- if(ev && in_czentry((rip),(entry))) { warn4(ERCIN_CZE,rip,length,&from,entry); continue; }
- #define CZEI(rip,entry) \
- if(ev && in_czentry((rip),(entry))) { warn4(ERCIN_CZE,rip,length,&from,entry); goto ignore_rip; }
-
- if(rip->rip_vers==0) {
- weakwarn3(ERCIN_VERS0,rip,length,&from);
- goto ignore_rip;
- }
- ev=(rip->rip_vers==RIPVERSION);
- CZI(rip->rip_res1[0]);
- CZI(rip->rip_res1[1]);
- if(rip->rip_cmd>RIPCMD_MAX) {
- if(ev) {
- warn3(ERCIN_UNKCMD,rip,length,&from);
- } else {
- weakwarn3(ERCIN_UNKCMD,rip,length,&from);
- }
- goto ignore_rip;
- }
-
- switch(rip->rip_cmd) {
- case 0:
- warn3(ERCIN_CMD0,rip,length,&from);
- goto ignore_rip;
- case RIPCMD_TRACEON:
- case RIPCMD_TRACEOFF:
- weakwarn3(ERCIN_CMD34,rip,length,&from);
- goto ignore_rip;
- case 5:
- weakwarn3(ERCIN_CMD5,rip,length,&from);
- goto ignore_rip;
-
- case RIPCMD_REQUEST:
- /* as silent process, we ignore rips from "normal" port */
- if(from.tba_port == g_routedport) {
- note3( ERCIN_IGNOREREQUEST, rip, length, &from );
- goto ignore_rip;
- }
- note3( ERCIN_GOTREQUEST, rip, length, &from );
- entry_count=in_countentries(length);
- if(entry_count==1 &&
- ntohs(rip->rip_nets[0].rip_dst.sa_family)==AF_UNSPEC &&
- ntohl(rip->rip_nets[0].rip_metric)==TBM_INFINITY) {
- CZEI(rip,0);
- note0( ERCIN_REQWHOLE );
- out_table(&from); /* send whole table */
- } else {
- for(entry=0; entry<entry_count; entry++) {
- CZE(rip,entry);
- ni=&rip->rip_nets[entry];
- if(ntohs(ni->rip_dst.sa_family) != AF_INET) {
- weakwarn4(ERCIN_UNKAF,rip,length,&from,entry);
- ni->rip_metric=htonl(TBM_INFINITY);
- continue;
- }
- ni->rip_metric=htonl(tb_rtmetric(ni->rip_dst));
- note5(ERCIN_REQENTRY,rip,length,&from,entry,ni->rip_metric);
- }
- note0( ERCIN_REQANSWER );
- out_rip(rip,length,&from,RIPCMD_RESPONSE);
- }
- break;
-
- case RIPCMD_RESPONSE:
- if(from.tba_port != g_routedport) {
- warn3(ERCIN_RESPPORT,rip,length,&from);
- goto ignore_rip;
- }
- /*** could check if allowed neighbour here! ***/
- /* check that this came from someone directly connected */
- if(from.tba_iface==-1) {
- warn3(ERCIN_RESPREMOTE,rip,length,&from);
- goto ignore_rip;
- }
- /**********************************************************
- * we can't be listening to ourselves, since we never *
- * respond to port g_routedport *
- **********************************************************/
- note3( ERCIN_GOTRESPONSE, rip, length, &from );
- entry_count=in_countentries(length);
- for(entry=0; entry<entry_count; entry++) {
- CZE(rip,entry);
- ni=&rip->rip_nets[entry];
- if(ntohl(ni->rip_metric) == 0 ||
- ntohl(ni->rip_metric) > TBM_INFINITY) {
- warn4(ERCIN_BADMETRIC,rip,length,&from,entry);
- continue;
- }
- dest.tba_addr=ni->rip_dst;
- dest.tba_addr.sa_family=ntohs(dest.tba_addr.sa_family);
- tb_chkaddr(&dest);
- if(dest.tba_af != AF_INET) {
- weakwarn4(ERCIN_UNKAF,rip,length,&from,entry);
- continue;
- }
- if( (dest.tba_flags & TBAF_VALID) == 0 ||
- ( (dest.tba_flags & TBAF_DEFAULT) == 0 &&
- ( (dest.tba_flags & TBAF_CLASSABC) == 0 ||
- dest.tba_subnet == 0 || dest.tba_subnet == 0x7f000000 ||
- (dest.tba_flags & TBAF_BROADCAST) ) ) ) {
- weakwarn4(ERCIN_BADADDR,rip,length,&from,entry);
- continue;
- }
- cost = ntohl(ni->rip_metric) +
- tb_iface[from.tba_iface].tbif_metric;
- if( cost > TBM_INFINITY ) cost=TBM_INFINITY;
- route = tb_findroute( &dest.tba_addr );
- note6(ERCIN_RESENTRY, rip, length, &from, entry, cost, route);
- if( route != -1 && tb_route[route].tbrt_flags & TBRTF_SUPERNET ) {
- warn1( ERCIN_RTSUPER, &dest );
- continue;
- }
- if( route == -1 ) {
- if(cost == TBM_INFINITY )
- continue;
- /* ignore host route if we have a decent net route */
- if( dest.tba_flags & TBAF_HOST ) {
- netroute = tb_findroute( &dest.tba_subnetsa );
- if( netroute != -1 && tb_route[netroute].tbrt_metric <= cost ) {
- note1( ERCIN_IGNOREHOST, netroute );
- continue;
- }
- }
- route = tb_newroute();
- if( route == -1 ) {
- warn0(ERCIN_RTFULL);
- continue;
- }
- tb_addroute( route, &dest, &from, cost );
- note1( ERCIN_RESADDED, route );
- } else {
- note0( ERCIN_HADROUTE );
- samegw = tb_samehost( &tb_route[route].tbrt_gateway,
- &from.tba_addr );
- if(samegw && cost == tb_route[route].tbrt_metric
- && (tb_route[route].tbrt_flags & TBRTF_DELETED) == 0
- && (tb_route[route].tbrt_flags & TBRTF_KILLED) == 0 ) {
- note0( ERCIN_REPEATROUTE );
- tm_settimeout( route );
- }
- if( (samegw && cost != tb_route[route].tbrt_metric)
- || cost < tb_route[route].tbrt_metric
- || (tb_route[route].tbrt_flags & TBRTF_TENTATIVE)
- || (tb_route[route].tbrt_flags & TBRTF_KILLED) ) {
- if( cost == TBM_INFINITY ) {
- note1( ERCIN_RESDELETED, route );
- tb_delroute( route, &from );
- } else {
- tb_addroute( route, &dest, &from, cost );
- note1( ERCIN_RESADDED, route );
- }
- } else {
- note0( ERCIN_RESIGNORED );
- }
- }
- }
- }
- ignore_rip:
- return;
- }
-